package xyz.tanxiao.query;

import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.Field;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

/**
 * 类属性工具类
 *
 * @author 万成波
 * @email 2300064869@qq.com
 * @createTime 2024-09-10 16:45:18 星期二
 */
@Slf4j
public class PropertyUtils {

	/**
	 * 获取类所有字段
	 *
	 * @param obj 类实例对象
	 * @return 类字段
	 */
	public static List<Field> getClassFields(Object obj) {
		Class<?> clazz = obj.getClass();
		List<Field> fields = new ArrayList<>(5);
		while (Objects.nonNull(clazz)){
			fields.addAll(Arrays.asList(clazz.getDeclaredFields()));
			clazz = clazz.getSuperclass();
		}
		return fields;
	}


	/**
	 * 获取类字段属性
	 *
	 * @param field 查询字段
	 * @param obj 类实例对象
	 * @return 字段属性
	 */
	public static FieldProperty getClassFieldProperty(Field field, Object obj) throws IllegalAccessException {
		field.setAccessible(true);
		FieldProperty property = new FieldProperty();
		property.setName(field.getName());
		property.setValue(field.get(obj));
		property.setType(field.getType());
		property.setTypeName(field.getType().getSimpleName());
		field.setAccessible(false);
		return property;
	}


	/**
	 * 获取类字段查询条件属性
	 *
	 * @param obj 类实例对象
	 * @return 查询条件属性
	 */
	public static List<ConditionProperty> getConditionProperties(Object obj) {
		// 反射解析类中的所有字段
		String className = obj.getClass().getName();
		List<Field> fields = getClassFields(obj);
		log.info("=> 解析类 {} 属性数量 {}", className, fields.size());

		List<ConditionProperty> condProperties = new ArrayList<>(fields.size());
		for (Field field : fields) {
			try {
				// 不处理未使用 @Condition 注解标注属性
				Condition condition = field.getAnnotation(Condition.class);
				if (Objects.isNull(condition)) {
					continue;
				}

				// 获取类字段属性
				FieldProperty fieldProperty = getClassFieldProperty(field, obj);

				// 封装类字段查询条件属性
				ConditionProperty condProperty = new ConditionProperty();
				condProperty.setProperty(fieldProperty);
				condProperty.setType(condition.type());
				condProperty.setValue(fieldProperty.getValue());
				condProperty.setFormat(condition.format());
				condProperty.setBetweenSlave(condition.betweenSlave());
				condProperty.setBetweenGroup(condition.betweenGroup());
				condProperty.setSortOrder(condition.sortOrder());

				// 属性名和数据库列名
				String propertyName = field.getName();
				condProperty.setPropertyName(propertyName);
				String columnName = condition.columnName();
				if (StringUtils.isNotBlank(columnName)) {
					condProperty.setColumnName(columnName);
				} else {
					condProperty.setColumnName(StringUtils.camelToUnderline(propertyName));
				}

				condProperties.add(condProperty);
			} catch (Exception e) {
				log.error("=> 解析类属性 {} 失败 {}", field.getName(), e.getMessage());
			}
		}

		log.info("=> 解析类 {} 查询条件属性数量 {}", className, fields.size());
		return condProperties;
	}


	/**
	 * 检查属性值是否为 null 或空字符串
	 *
	 * @param value 属性值
	 * @return 是否不为 null 或空字符串
	 */
	public static boolean isNullOrEmptyValue(Object value) {
		if (Objects.isNull(value)) {
			return true;
		}
		if (value instanceof String && ((String) value).isEmpty()) {
			return true;
		}
		return (value instanceof Collection) && ((Collection<?>) value).isEmpty();
	}


	/**
	 * 获取集合属性的属性值
	 *
	 * @param value 属性值
	 * @return 集合属性值
	 */
	public static Collection<?> getCollectionValues(Object value) {
		if (value instanceof Collection<?>) {
			return (Collection<?>) value;
		} else {
			return Collections.emptyList();
		}
	}


	/**
	 * 将属性值按照指定格式进行格式化 (主要是针对日期时间格式化)
	 *
	 * @param value 属性值
	 * @param format 格式
	 * @return 属性值字符串
	 */
	public static Object formatValue(Object value, String format) {
		if (Objects.isNull(value) || StringUtils.isBlank(format)) {
			return value;
		}
		if (value instanceof String) {
			return String.valueOf(value);
		}
		else if (value instanceof Date) {
			return new SimpleDateFormat(format).format((Date) value);
		}
		else if (value instanceof LocalDate) {
			return DateTimeFormatter.ofPattern(format).format((LocalDate) value);
		}
		else if (value instanceof LocalDateTime) {
			return DateTimeFormatter.ofPattern(format).format((LocalDateTime) value);
		}
		return value;
	}

}
